Skip to main content

Lections

8. Procedure Language

Внутренний язык СУБД. Сравнительные характеристики T-SQL и PL/SQL.

Введение​

Практически каждая СУБД имеет в своем составе процедурное расширение языка SQL. Эти языки используются для реализации бизнес-логики и дополнительных проверок целостности на уровне сервера. Программные модули, написанные на этих языках, хранятся в СУБД и выполняются специальным компонентом непосредственно в ядре СУБД. Синтаксис таких языков разработан для максимально простой и удобной интеграции с SQL. Модули процедурного расширения SQL могут быть одного из следующих типов

  1. Хранимые процедуры, пакеты, функции
  2. Триггеры
  3. Безымянные блоки

Oracle. Процедурное расширение - PL/SQL. Синтаксис похож на ADA. Помимо СУБД, входит в другие продукты Oracle, например Oracle Developer. Является наиболее мощным из процедурных языков основных СУБД.
SQL Server. Процедурное расширение - Transact-SQL (T-SQL). Обладает основными возможностями. Дл версии 2005 отсутствовала обработка исключений.
Основные характеристики PL/SQL и T-SQL

  • Полный диапазон типов данных
  • Явно определяемая структура кода - блоки данных, процедуры и т.д.
  • Операторы управления потоком команд - условные, циклы и т.д.
  • Обработчики исключений
  • Повторно используемые именованные блоки кода, такие как функции, процедуры, пакеты (только в PL/SQL)
  • Тесная интеграция с SQL - непосредственный вызов команд SQL из процедурного кода

Блок PL/SQL. Структура​

Вызов из sqlplus:​

call dbms_output.put_line('aaa')
exec dbms_output.put_line('aaa')

Структура блока plsql​

declare
i number;
d date;
begin
i := 0;

select count(*) into i from all_users;

if i > 10 then
dbms_output.put_line('> 10');
else
dbms_output.put_line('<= 10');
end if;

begin
select sysdate into d from dual;
exception
when no_data_found then
d := null;
raise;
end;
end;

Основные элементы plsql​
Комментарии​

/*
многострочные
комментарии
*/

Идентификаторы​

declare
LongName number;
begin
longname := 10;
dbms_output.put_line(LONGNAME);
end;

declare
"LongName" number;
begin
longname := 10;
dbms_output.put_line(LONGNAME);
end;

declare
n_$# number;
begin
n_$# := 10;
end;

Логический тип​

declare
b boolean;
begin
b := true;
-- error
-- dbms_output.put_line(b);

dbms_output.put_line(case b when true then 1 else 0 end);

if b then
dbms_output.put_line(1);
else
dbms_output.put_line(0);
end if;
end;

Декларации​

declare
n1 number;
n2 number := 10;
n3 number default 10;
n4 number not null := 30;
begin
dbms_output.put_line(nvl(n1, -100));
dbms_output.put_line(n2);
dbms_output.put_line(n3);
dbms_output.put_line(n4);
end;

declare
n test.i%type;
r test%rowtype;
begin
n := 10;
dbms_output.put_line(n);

select * into r from test where i = 1;
dbms_output.put_line(r.i);
dbms_output.put_line(r.s);
end;

-- видимость переменных
declare
a number := 10;
b number := 20;
begin
dbms_output.put_line(a);
dbms_output.put_line(b);

declare
a number;
c number;
begin
a := 30;
c := 40;
dbms_output.put_line('---->'||a);
dbms_output.put_line('---->'||b);
dbms_output.put_line('---->'||c);
end;

dbms_output.put_line(a);
dbms_output.put_line(b);
end;

Именованные блоки​

<<my_block>>
declare
a number := 10;
b number := 20;
begin
dbms_output.put_line(a);
dbms_output.put_line(b);

declare
a number;
c number;
begin
a := 30;
c := 40;
dbms_output.put_line('---->'||my_block.a);
dbms_output.put_line('---->'||a);
dbms_output.put_line('---->'||b);
dbms_output.put_line('---->'||c);
end;

dbms_output.put_line(a);
dbms_output.put_line(b);
end;

<<my_block1>>
declare
a number := 10;
begin
dbms_output.put_line('my_block1 '||a);

<<my_block2>>
declare
a number := 20;
begin
dbms_output.put_line('my_block2 '||my_block1.a);
dbms_output.put_line('my_block2 '||a);

<<my_block3>>
declare
a number := 30;
begin
dbms_output.put_line('my_block3 '||my_block1.a);
dbms_output.put_line('my_block3 '||my_block2.a);
dbms_output.put_line('my_block3 '||a);
end;
end;

dbms_output.put_line('my_block1 '||a);
end;

Управляющие конструкции​

declare
n number;
begin
n := 10;

if n > 10 then
n := 20;
dbms_output.put_line(n);
else
n := 30;
dbms_output.put_line(n);
end if;

if n > 10 then
n := 20;
dbms_output.put_line(n);
end if;

if n > 10 then
n := 20;
dbms_output.put_line(n);
elsif n > 5 then
n := 30;
dbms_output.put_line(n);
else
n := 40;
dbms_output.put_line(n);
end if;

case n
when 10 then
n := 100;
dbms_output.put_line(n);
when 12 then
n := 200;
dbms_output.put_line(n);
else
n := 300;
dbms_output.put_line(n);
end case;

case
when n = 10 then
n := 100;
dbms_output.put_line(n);
when n = 12 then
n := 200;
dbms_output.put_line(n);
else
n := 300;
dbms_output.put_line(n);
end case;
end;

declare
n number := 10;
begin
case n
when 1 then
dbms_output.put_line('1');
when 2 then
dbms_output.put_line('1');
end case;
exception
when case_not_found then
dbms_output.put_line('case not found');
end;

declare
n number;
begin
n := 1;

loop
dbms_output.put_line(n);
n := n+1;
exit when n > 10;
end loop;
end;

declare
n number;
begin
n := 1;

loop
dbms_output.put_line(n);
n := n+1;
if n > 10 then
exit;
end if;
end loop;
end;

declare
n number;
begin
n := 1;

while n <= 10 loop
dbms_output.put_line(n);
n := n+1;
end loop;
end;

declare
n number;
begin
for n in 1..10 loop
dbms_output.put_line(n);
end loop;
end;

declare
n number;
begin
for n in reverse 1..10 loop
dbms_output.put_line(n);
end loop;
end;

Неявное использование переменной цикла​

declare
n number := 100;
begin
for n in 1..10 loop
dbms_output.put_line(n);
end loop;
dbms_output.put_line('after ' || n);
end;

declare
n number;
begin
for i in 1..10 loop
n := i;
dbms_output.put_line(n || ' ' || i);
-- error
-- i := 20;
end loop;
dbms_output.put_line(n);
end;

Динамическое изменение границ​

declare
n number := 3;
begin
for i in 1..n loop
if n < 10 then
n := n+1;
end if;
dbms_output.put_line(i || ' ' || n);
end loop;
end;

Использование меток​

begin
<<l1>>
for i in 1..3 loop
for i in 5..6 loop
dbms_output.put_line(l1.i || ' ' || i);
end loop;
end loop;
end;

begin
<<l1>>
for i in 1..3 loop
for i in 5..6 loop
dbms_output.put_line(l1.i || ' ' || i);
exit l1 when i = 5;
end loop;
end loop;
end;

-- goto
declare
n number;
begin
if n = null then
dbms_output.put_line('in if');
else
goto met1;
end if;
dbms_output.put_line('after if');

<<met1>>
dbms_output.put_line('after met1');
end;

declare
n number := 1;
begin
for i in 1..10 loop
if i = 5 then
goto cont;
end if;
n := n+1;
dbms_output.put_line(n);
<<cont>>
null;
end loop;
end;

Основные объекты. Хранимые процедуры и функции​

Хранимая процедура или функция - это подпрограмма, состоящая из SQL операторов и команд процедурного языка. Хранимая процедура и функция может:

  • Содержать параметры (аргументы);
  • Вызывать другие процедуры;
  • Возвращать свой статус вызывающей процедуре или пакету, указывающий на успешное окончание или ошибку, и в случае ошибки на ее причину;
  • Возвращать значения параметров вызывающей процедуре или пакету;
  • Выполняется всегда на стороне сервера.
  • Функция кроме того возвращает результат через свое имя.

Хранимые процедуры и функции значительно увеличивают мощность, эффективность и гибкость языка SQL и значительно ускоряют выполнение SQL-операторов и пакетов.
Хранимые процедуры создаются с помощью команды create procedure. Функции создаются с помощью команды - create function. Для выполнения хранимой процедуры, как системной, так и определенной пользователем, используется команда execute (выполнить). Можно также просто указать название хранимой процедуры, если оно является первым словом в операторе или пакете.
Хранимая процедура или функция имеет две части:

  • Спецификация, которая объявляет процедуру или функцию и состоит из следующей информации:
    • Имени процедуры
    • Имен и типов данных аргументов, если есть
    • Кроме этого, ТОЛЬКО для функций - типа данных возвращаемого значения
  • Тело, которое определяет процедуру или функцию. Тело процедуры состоит из блока PL/SQL или T-SQL (который содержит предложения SQL и процедурного расширения).

Основные объекты. Триггеры​

Триггер - это хранимая процедура специального вида, которая запускается при возникновении какого-либо события, обычно изменения данных в таблице. В частности, триггеры помогают сохранить ссылочную целостность данных пользователя, проверяя их согласованность в логически связанных таблицах. Основным достоинством триггеров является то, что они вызываются автоматически. Они будут работать независимо от причины, которая вызвала модификацию данных, как, например, после ввода данных клерком, так и при выполнении некоторой прикладной процедуры. Триггер может быть связан с одним или несколькими операторами модификации, такими как update, insert или delete.